// Copyright (c) 2010 Manuel Peinado Gallego <manuel.peinado@gmail.com>
// Distributed under the MIT license

// ActionManager.cpp : implementation of the ActionManager class
//

#include "stdafx.h"
#include "ActionManager.h"
#include "NodeManager.h"
#include "LogManager.h"
#include "Ui.h"

#ifdef _DEBUG
#define new DEBUG_NEW
#endif


// ActionManager

ActionManager::ActionManager(World* w, Ui* ui)
: WorldFollower(WorldFollower::ListenNothing)
{
    setWorld(w);
    setUi(ui);
}

// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 

void ActionManager::postAction(ref<Action> action)
{
    m_actionQueue.add(action);
}

void ActionManager::performNext()
{
    // performNext is supposed to be called always from the same thread but
    // just in case we make the whole thing atomic
    ZThread::Guard<ZThread::Mutex> guard(m_actionQueueMutex);

    if(m_actionQueue.empty())
    {
        return;
    }

    performAction(m_actionQueue.next());
}

// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 

void ActionManager::performAction(ref<Action> action)
{
    getUi().getLogManager().addLogMessage(action->description());

    action->perform(getWorld());

    // TODO set a limit on the maximum of stored actions
    m_undoActions.push_front(action);

    m_redoActions.clear();
}

// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 

bool ActionManager::canUndo() const
{
    return !m_undoActions.empty();
}

void ActionManager::undo()
{
    ASSERT(canUndo());

    getUi().getLogManager().addLogMessage(
    	"Undo: " + m_undoActions.front()->description());

    m_undoActions.front()->revert(getWorld());
    m_redoActions.push_front(m_undoActions.front());
    m_undoActions.pop_front();
}

// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 

bool ActionManager::canRedo() const
{
    return !m_redoActions.empty();
}

void ActionManager::redo()
{
    ASSERT(canRedo());

    getUi().getLogManager().addLogMessage(
    	"Redo: " + m_redoActions.front()->description());

    m_redoActions.front()->perform(getWorld());
    m_undoActions.push_front(m_redoActions.front());
    m_redoActions.pop_front();
}

